/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <memory>
#include <mutex>
#include "kh_sle_ssap_server.h"
#include "sle_ssap_server_interface.h"
#include "sle_hilog.h"

#ifdef __cplusplus
extern "C" {
#endif

namespace OHOS {
namespace NearLink {
namespace SleStandard {
#define SLE_MAX_SSAP_SERVER_CALLBACK_NUM  3

static SleSsapServer* g_ssapServers[SSAP_SERVER_NUM_MAX] = {nullptr};
static SleSsapsCallbacks* g_ssapServerCallbacks[SLE_MAX_SSAP_SERVER_CALLBACK_NUM] = {nullptr};
static std::mutex g_ssapsCbLock;


class SleSsapServerCallbackWapper : public SleSsapServerCallback {
public:
    SleSsapServerCallbackWapper(uint8_t serverId)
    {
        serverId_ = serverId;
    }

    void OnReadRequest(uint16_t connectId, const SsapsReqReadCbParam &readCbPara, SleErrorCode errCode) override
    {
        std::lock_guard<std::mutex> lock(g_ssapsCbLock);
        for (int i = 0; i < SLE_MAX_SSAP_SERVER_CALLBACK_NUM; i++) {
            if (g_ssapServerCallbacks[i] != nullptr && g_ssapServerCallbacks[i]->OnRequestReadCb != nullptr) {
                g_ssapServerCallbacks[i]->OnRequestReadCb(errCode, serverId_, connectId, &readCbPara);
            }
        }
    }

    void OnWriteRequest(uint16_t connectId, const SsapsReqWriteCbPara &writeCbPara, SleErrorCode errCode) override
    {
        std::lock_guard<std::mutex> lock(g_ssapsCbLock);
        for (int i = 0; i < SLE_MAX_SSAP_SERVER_CALLBACK_NUM; i++) {
            if (g_ssapServerCallbacks[i] != nullptr && g_ssapServerCallbacks[i]->OnRequestWriteCb != nullptr) {
                g_ssapServerCallbacks[i]->OnRequestWriteCb(errCode, serverId_, connectId, &writeCbPara);
            }
        }
    }

    void OnMtuInfoChanged(uint16_t connectId, const SsapMtuInfo &info, SleErrorCode errCode) override
    {
        std::lock_guard<std::mutex> lock(g_ssapsCbLock);
        for (int i = 0; i < SLE_MAX_SSAP_SERVER_CALLBACK_NUM; i++) {
            if (g_ssapServerCallbacks[i] != nullptr && g_ssapServerCallbacks[i]->OnChangeMtuCb != nullptr) {
                g_ssapServerCallbacks[i]->OnChangeMtuCb(errCode, serverId_, connectId, &info);
            }
        }
    }

private:
    uint8_t serverId_;
};

static std::shared_ptr<SleSsapServerCallbackWapper> g_ssapServerCbWapper[SSAP_SERVER_NUM_MAX] = {nullptr};

SleErrorCode InitSleSsapsService()
{
    SLE_LOGI("InitSleSsapsService");
    return SLE_NO_ERROR;
}

SleErrorCode DeinitSleSsapsService()
{
    SLE_LOGI("DeinitSleSsapsService");
    return SLE_NO_ERROR;
}

SleErrorCode AddSsapServer(const SleUuid *appUuid, uint8_t *serverId)
{
    SLE_LOGI("AddSsapServer");
    SLE_ASSERT_AND_RETURN_RET_LOG(appUuid, SLE_ERR_INVALID_PARAM, "param server uuid error!");
    SleErrorCode ret = SLE_ERR_FAILED;
    for (uint8_t i = 0; i < SSAP_SERVER_NUM_MAX; i++) {
        if (g_ssapServers[i] == nullptr) {
            g_ssapServerCbWapper[i] = std::make_shared<SleSsapServerCallbackWapper>(i);
            g_ssapServers[i] = new SleSsapServer(*appUuid);
            *serverId = i;
            ret = g_ssapServers[i]->RegisterServerCallback(g_ssapServerCbWapper[i]);
            SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add ssap server failed!");
            return SLE_NO_ERROR;
        }
    }
    return ret;
}

SleErrorCode RemoveSsapServer(uint8_t serverId)
{
    SLE_LOGI("RemoveSsapServer");
    if (serverId >= 0 && serverId < SSAP_SERVER_NUM_MAX) {
        if (g_ssapServers[serverId] != nullptr) {
            delete g_ssapServers[serverId];
            g_ssapServers[serverId] = nullptr;
            return SLE_NO_ERROR;
        } else {
            SLE_LOGE("server id not add error!");
            return SLE_ERR_INVALID_PARAM;
        }
    } else {
        SLE_LOGE("param server id error!");
        return SLE_ERR_INVALID_PARAM;
    }
    return SLE_ERR_FAILED;
}

SleErrorCode AddService(uint8_t serverId, const SleUuid *serviceUuid, bool isPrimary, uint16_t *srviceHandle)
{
    SLE_LOGI("AddService");
    if (serverId < 0 || serverId >= SSAP_SERVER_NUM_MAX) {
        SLE_LOGE("param server id error!");
        return SLE_ERR_INVALID_PARAM;
    }
    SLE_ASSERT_AND_RETURN_RET_LOG(serviceUuid, SLE_ERR_INVALID_PARAM, "param service uuid error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->AddService(*serviceUuid, isPrimary, *srviceHandle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add service failed!");
    return SLE_NO_ERROR;
}

SleErrorCode AddProperty(uint8_t serverId, uint16_t serviceHandle, const SsapsPropertyParam *propertyParam, uint16_t *propHandle)
{
    SLE_LOGI("AddProperty");
    if (serverId < 0 || serverId >= SSAP_SERVER_NUM_MAX) {
        SLE_LOGE("param server id error!");
        return SLE_ERR_INVALID_PARAM;
    }
    SLE_ASSERT_AND_RETURN_RET_LOG(propertyParam, SLE_ERR_INVALID_PARAM, "param property error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->AddProperty(serviceHandle, *propertyParam, *propHandle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add property failed!");
    return SLE_NO_ERROR;
}

SleErrorCode AddDescriptor(uint8_t serverId, uint16_t serviceHandle, uint16_t propHandle
        , const SsapsDescriptorParam *descParam, uint16_t *descHandle)
{
    SLE_LOGI("AddDescriptor");
    if (serverId < 0 || serverId >= SSAP_SERVER_NUM_MAX) {
        SLE_LOGE("param server id error!");
        return SLE_ERR_INVALID_PARAM;
    }
    SLE_ASSERT_AND_RETURN_RET_LOG(descParam, SLE_ERR_INVALID_PARAM, "param descriptor error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->AddDescriptor(serviceHandle, propHandle, *descParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "add descriptor failed!");
    return SLE_NO_ERROR;
}

SleErrorCode RemoveAllServices(uint8_t serverId)
{
    SLE_LOGI("RemoveAllServices");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->RemoveAllServices();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "remove all services failed!");
    return SLE_NO_ERROR;
}

SleErrorCode StartService(uint8_t serverId, uint16_t serviceHandle)
{
    SLE_LOGI("StartService");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->StartService(serviceHandle);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "start service failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SendResponse(uint8_t serverId, uint16_t connectId, const SsapsSendRspParam *param)
{
#if 0
    SLE_LOGD("SendResponse");
#endif
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->SendResponse(connectId, *param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "send response failed!");
    return SLE_NO_ERROR;
}

SleErrorCode NotifyIndicate(uint8_t serverId, uint16_t connectId, const SsapsNotifyParam *param)
{
#if 0
    SLE_LOGD("NotifyIndicate");
#endif
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->NotifyIndicate(connectId, *param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "notify indicate failed!");
    return SLE_NO_ERROR;
}

SleErrorCode NotifyIndicateByUuid(uint8_t serverId, uint16_t connectId, const SsapsNotyfyByUuidParam *param)
{
#if 0
    SLE_LOGD("NotifyIndicateByUuid");
#endif
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->NotifyIndicateByUuid(connectId, *param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "notify indicate by uuid failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SetServerMtuInfo(uint8_t serverId, const SsapMtuInfo *mtuInfo)
{
    SLE_LOGI("SetServerMtuInfo");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServers[serverId], SLE_ERR_INVALID_PARAM, "no server error!");
    SleErrorCode ret = g_ssapServers[serverId]->SetServerMtuInfo(*mtuInfo);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "set mtu info failed!");
    return SLE_NO_ERROR;
}

SleErrorCode RegisterSsapServerCallbacks(SleSsapsCallbacks *ssapsCallback)
{
    SLE_LOGI("RegisterSsapServerCallbacks");
    SLE_ASSERT_AND_RETURN_RET_LOG(ssapsCallback, SLE_ERR_INVALID_PARAM, "ssap server callback error!");
    std::lock_guard<std::mutex> lock(g_ssapsCbLock);
    for(int i = 0; i < SLE_MAX_SSAP_SERVER_CALLBACK_NUM; i++) {
        SLE_ASSERT_AND_RETURN_RET_LOG(g_ssapServerCallbacks[i] != ssapsCallback, SLE_ERR_INVALID_PARAM, "server callback has registered!");
    }
    SleErrorCode ret = SLE_ERR_FAILED;
    for(int i = 0; i < SLE_MAX_SSAP_SERVER_CALLBACK_NUM; i++) {
        if (g_ssapServerCallbacks[i] == nullptr) {
            g_ssapServerCallbacks[i] = ssapsCallback;
            ret = SLE_NO_ERROR;
            break;
        }
    }
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "register server callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode UnregisterSsapServerCallbacks(SleSsapsCallbacks *ssapsCallback)
{
    SLE_LOGI("UnregisterSsapServerCallbacks");
    SLE_ASSERT_AND_RETURN_RET_LOG(ssapsCallback, SLE_ERR_INVALID_PARAM, "ssap server callback error!");
    bool registered = false;
    std::lock_guard<std::mutex> lock(g_ssapsCbLock);
    for(int i = 0; i < SLE_MAX_SSAP_SERVER_CALLBACK_NUM; i++) {
        if (g_ssapServerCallbacks[i] == ssapsCallback) {
            g_ssapServerCallbacks[i] = nullptr;
            registered = true;
            break;
        }
    }
    SLE_ASSERT_AND_RETURN_RET_LOG(registered == true, SLE_ERR_INVALID_PARAM, "server callback has not registered!");
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS

#ifdef __cplusplus
}
#endif